
"use strict";
var ForceSimulation = function(graph,data){
    // 默认配置
    var DEFAULT_WIDTH　= 400,
          DEFAULT_HEIGHT = 500,
          DEFAULT_STROKE = '#999',
          DEFAULT_STROKE_WIDTH_HIDDEN = '0px',
          DEFAULT_STROKE_WIDTH_SHOW = '2px',
          DEFAULT_STROKE_DASHARRAY = 0,
          DEFAULT_OPACITY_SHOW = 1,
          DEFAULT_OPACITY_HIDDEN = 0,
          DEFAULT_CIRCLE_RADIUS = 6,
          DEFAULT_STRENGTH = 1,
          DEFAULT_CHARGE = -100,
          DEFAULT_DISTANCE = 60,
          LINK_ARROW_POSITIVE = 'positive',
          LINK_ARROW_REVERSE = 'reverse',
          LINK_ARROW_TWOWAY = 'twoway';
    // Graph svg, graph 布局
    var graphSvg,graphData,graphBrush,graphBrushFlag,simulation,
        graphWidth = DEFAULT_WIDTH,
        graphHeight = DEFAULT_HEIGHT,
        graphStrength = DEFAULT_STRENGTH,
        graphCharge = DEFAULT_CHARGE,
        graphDistance = DEFAULT_DISTANCE;
    // Graph zoom,brush,drag
    var graphZoom,brushSvg,zoomedTransform,graphDrag;
    // 力图
    var forceLinkText,forceLink,forceNodeText,forceNode;
    // 事件监听
    var graphListeners;
    // force graph
    var ForceGraph = {
        /**
        * 构造方法
        *
        * @param {object} graph - 附着对象
        * @param {object} data  - 图数据
        */
        constructor: function( graph, _data){
            this.graph = graph;
            this.data = _data;
            return this;
        },
        /**
        * 初始化graph 参数
        */
        initGraph: function(){
            // 宽度
            if(this.data.width)graphWidth = this.data.width;
            // 高度
            if(this.data.height)graphHeight = this.data.height;
            // 事件监听
            if(this.data.listeners)graphListeners = this.data.listeners;
            // 电荷强度
            if(this.data.strength)graphStrength = this.data.strength;
            // 电荷大小
            if(this.data.charge)graphCharge = this.data.charge;
            // 电荷最小距离
            if(this.data.distance)graphDistance = this.data.distance;
            // brush 层
            if(this.data.brush)graphBrushFlag = this.data.brush;
            // graph 数据
            var dataInfo = this.data.data;
            if(!dataInfo || !dataInfo.nodes){
                graphData = {nodes:[],links:[]};
                console.log('数据不完整，无法生成图');
            }else{
                graphData = dataInfo;
            }
            // 初始化大小
            this.graph.attr('width', graphWidth )
                      .attr('height', graphHeight )
                      .on('mousedown', function(){
                          if(graphListeners && graphListeners.click){
                              graphListeners.click(d3.event,{nodes:[],links:[]});
                          }
                      });
            this.generateForce();
        },
        /**
        * 生成 Force
        *
        * @param {object} graph - 附着对象
        * @param {object} data  - 图数据
        */
        generateForce: function(){
            // graph content
            graphSvg = this.graph.append('svg:g')
                                      .attr('class','graphContent');
            // 箭头定义
            var svgDefs = graphSvg.append('svg:defs')
                                       .attr('class','graphDefine');
            // 开始箭头
            svgDefs.append('svg:marker')
                  .attr('id', 'start-arrow')
                  .attr('viewBox', '0 -5 10 10')
                  .attr('refX', 6)
                  .attr('markerWidth', 3)
                  .attr('markerHeight', 3)
                  .attr('orient', 'auto')
                  .append('svg:path')
                  .attr('d', 'M10,-5L0,0L10,5')
                  .attr('fill', DEFAULT_STROKE);
            // 结束箭头
            svgDefs.append('svg:marker')
                  .attr('id', 'end-arrow')
                  .attr('viewBox', '0 -5 10 10')
                  .attr('refX', 6)
                  .attr('markerWidth', 3)
                  .attr('markerHeight', 3)
                  .attr('orient', 'auto')
                  .append('svg:path')
                  .attr('d', 'M0,-5L10,0L0,5')
                  .attr('fill', DEFAULT_STROKE);
            // forceSimulation
            simulation = d3.forceSimulation()
                            .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(graphDistance))
                            .force("charge", d3.forceManyBody().strength(graphCharge))
                            .force("center", d3.forceCenter(graphWidth/2,graphHeight/2))
                            .force('strength', d3.forceManyBody().strength(graphStrength))
                            .force('x', d3.forceX(graphWidth / 2).strength(0.1))
                            .force('y', d3.forceY(graphHeight / 2).strength(0.1));
            // brush content
            brushSvg = this.graph.append('svg:g')
                                      .attr('class','brushContent')
                                      .append('g')
                                      .attr('class','brush');
            // brush
            graphBrush = d3.brush()
                                .on("start", this.brushStart)
                                .on("brush", this.brushMove)
                                .on("end", this.brushEnd)
                                .extent([[0,0],[graphWidth,graphHeight]]);
            // drag
            this.graphDrag = d3.drag()
                                .on("start", this.dragstarted)
                                .on("drag", this.dragged)
                                .on("end", this.dragended);
            // 缩放
            graphZoom = d3.zoom().on("zoom", this.zoomed);
            // 添加到graph
            this.graph.call(graphZoom);
            // 绘制
            this.redrawedForce();
        },
        /**
        *  缩放zoom
        */
        zoomed: function(){
            // svg 缩放
            zoomedTransform = d3.event.transform;
            graphSvg.attr("transform", d3.event.transform);
            brushSvg.attr("transform", d3.event.transform);
            // 平移、缩放比例
            var x = d3.event.transform.x,
                y = d3.event.transform.y,
                k = d3.event.transform.k;
            // brush 层范围
            var extent = [
                [0 - x / k, 0 - y / k],
                [(graphWidth - x) / k, (graphHeight - y) / k]
            ];
            graphBrush.extent(extent);
            // 选择层
            if(graphBrushFlag){
                brushSvg.select('.brush').call(graphBrush);
            }
        },
        /**
        *  拖拽开始
        */
         dragstarted: function( d ) {
            if (!d3.event.active) simulation.alphaTarget(0.3).restart();
            d.fx = d.x;
            d.fy = d.y;
        },
        /**
        *  拖拽中
        */
         dragged: function( d ) {
            var _mx = d3.event.sourceEvent.movementX,
				_my = d3.event.sourceEvent.movementY;
            graphSvg.selectAll('.node.selected').each(function(d){
                if(zoomedTransform){
                    d.fx = d.x + _mx/zoomedTransform.k;
                    d.fy = d.y + _my/zoomedTransform.k;
                }else{
                    d.fx = d.x + _mx;
                    d.fy = d.y + _my;
                }
			});
            // TODO
            d.fx = d3.event.x;
            d.fy = d3.event.y;
        },
        /**
        *  拖拽结束
        */
        dragended: function( d ) {
            // if (!d3.event.active) simulation.alphaTarget(0);
            d.fx = d.x;
            d.fy = d.y;
        },
        /**
        *  brush开始
        */
        brushStart: function(){
            brushSvg.select('.selection')
                        .attr('fill-opacity',0.125)
                        .attr('stroke-width',1);
        },
        /**
        *  brush移动
        */
        brushMove: function(){
            // 刷子选中项
            var selection = d3.event.selection;
            forceNode.classed("selected", function( d ) {
                if(selection){
                    return selection[0][0] <= d.x && d.x < selection[1][0]
                        && selection[0][1] <= d.y && d.y < selection[1][1];
                }
            });
        },
        /**
        *  brush结束
        */
        brushEnd: function(){
            if(graphListeners && graphListeners.selected){
                var selectedData = graphSvg.selectAll('.selected').data();
                if(selectedData.length){
                    graphListeners.selected(d3.event,{nodes:selectedData,links:[]});
                }else{
                    graphListeners.selected(d3.event,{nodes:[],links:[]});
                }
            }
        },
        /**
        * 绘制 Force
        */
        redrawedForce: function(){
            var _this = this;
            // 关系名称
            graphSvg.selectAll('.linetexts').remove();
            forceLinkText = graphSvg.append('g').attr('class','linetexts')
                            .selectAll(".linetext")
                            .data(graphData.links,function(d){return d})
                            .enter().append("text")
                            .attr("class","linetext")
                            .attr("fill-opacity",function(d){
                                return _this.setStyleForText(d,'opacity');
                            })
                            .style('stroke',function(d){
                                return _this.setStyleForText(d,'stroke');
                            })
                            .style('stroke-width',function(d){
                                return _this.setStyleForText(d,'stroke-width');
                            })
                            .style('stroke-dasharray',function(d){
                                return _this.setStyleForText(d,'stroke-dasharray');
                            })
                            .html(function(d){ return (typeof d.title != 'undefined')?d.title:d.id;});
            forceLinkText.exit().remove();
            // 节点名称
            graphSvg.selectAll('.nodetexts').remove();
            forceNodeText = graphSvg.append('g').attr('class','nodetexts')
                            .selectAll(".nodetext")
                            .data(graphData.nodes,function(d){return d})
                            .enter().append("text")
                            .attr("class","nodetext")
                            .attr("fill-opacity",function(d){
                                return _this.setStyleForText(d,'opacity');
                            })
                            .style('stroke',function(d){
                                return _this.setStyleForText(d,'stroke');
                            })
                            .style('stroke-width',function(d){
                                return _this.setStyleForText(d,'stroke-width');
                            })
                            .style('stroke-dasharray',function(d){
                                return _this.setStyleForText(d,'stroke-dasharray');
                            })
                            .html(function(d){ return (typeof d.title != 'undefined')?d.title:d.id;});
            forceNodeText.exit().remove();
            // 关系
            graphSvg.selectAll('.links').remove();
            forceLink = graphSvg.append('g').attr('class','links').selectAll('.link')
                        .data(graphData.links,function(d){return d;})
                        .enter().append('svg:path')
                        .attr('class', 'link')
                        .attr('id',function(d){return d.id;})
                        .style('stroke',function(d){
                            return _this.setStyleForNodeOrLink(d,'stroke');
                        })
                        .style('stroke-width',function(d){
                            return _this.setStyleForNodeOrLink(d,'stroke-width');
                        })
                        .style('stroke-dasharray',function(d){
                            return _this.setStyleForNodeOrLink(d,'stroke-dasharray');
                        })
                        .style('opacity',function(d){
                            return _this.setStyleForNodeOrLink(d,'opacity');
                        })
                        .style('marker-start',function(d){
                            if(d.arrow === LINK_ARROW_REVERSE || d.arrow === LINK_ARROW_TWOWAY){
                                return 'url(#start-arrow)';
                            }
                        })
                        .style('marker-end', function(d) {
                            if(d.arrow === LINK_ARROW_POSITIVE || d.arrow === LINK_ARROW_TWOWAY){
                                return 'url(#end-arrow)';
                            }
                        })
                        .on('mousedown',function(d){
                            d3.event.preventDefault();
                            d3.event.stopImmediatePropagation();
                            if(graphListeners && graphListeners.click){
                                graphListeners.click(d3.event,{nodes:[],links:[d]});
                            }
                        });
            forceLink.exit().remove();
            // 节点
            graphSvg.selectAll('.nodes').remove();
            forceNode = graphSvg.append('g').attr('class','nodes').selectAll('.node')
                        .data(graphData.nodes, function(d) { return d.id; })
                        .enter().append(function(d){
                            if(d.style && d.style.icon && d.style.icon.key){
                                _this.defineImage(d.style.icon);
                                return document.createElementNS(d3.namespaces.svg,'rect');
                            }
                            return document.createElementNS(d3.namespaces.svg,'circle');
                        })
                        .attr('class', 'node')
                        .attr('stroke',function(d){
                            return _this.setStyleForNodeOrLink(d,'stroke');
                        })
                        .attr('stroke-width',function(d){
                            return _this.setStyleForNodeOrLink(d,'stroke-width');
                        })
                        .attr('stroke-dasharray',function(d){
                            return _this.setStyleForNodeOrLink(d,'stroke-dasharray');
                        })
                        .attr('opacity',function(d){
                            return _this.setStyleForNodeOrLink(d,'opacity');
                        })
                        .attr('width',function(d){
                            return _this.setStyleForNodeOrLink(d,'width');
                        })
                        .attr('height',function(d){
                            return _this.setStyleForNodeOrLink(d,'height');
                        })
                        .attr('r', function(d){
                            return _this.setStyleForNodeOrLink(d,'radius');
                        })
                        .attr("fill", function(d){
                            return _this.setStyleForNodeOrLink(d,'fill');
                         })
                        .on('mousedown',function(d){
                            if(d3.event.which === 3){
                                d3.event.stopPropagation();
                            }
                            // 调用选中事件
                            if(graphListeners && graphListeners.click){
                                graphListeners.click(d3.event,{nodes:[d],links:[]});
                            }
                        });
            forceNode.exit().remove();
            forceNode.call(this.graphDrag);
            // 生成
            simulation.nodes(graphData.nodes).on("tick", this.graphTick);
            simulation.force('link').links(graphData.links);
            simulation.alpha(1).restart();
        },
        // 设置文本样式
        setStyleForText: function(d,propName){
            var propValue = '';
            switch (propName) {
                case 'opacity':
                    if(d.style && d.style.text && d.style.text.opacity){
                        propValue = d.style.text.opacity;
                    }else{
                        propValue = DEFAULT_OPACITY_HIDDEN;
                    }
                    break;
                case 'stroke':
                    if(d.style && d.style.text && d.style.text.stroke){
                        propValue = d.style.text.stroke;
                    }else{
                        propValue = DEFAULT_STROKE;
                    }
                    break;
                case 'stroke-width':
                    if(d.style && d.style.text && d.style.text.strokeWidth){
                        return d.style.text.strokeWidth;
                    }else{
                        return DEFAULT_STROKE_WIDTH_HIDDEN;
                    }
                    break;
                case 'stroke-dasharray':
                    if(d.style && d.style.text && d.style.text.strokeDasharray){
                        return d.style.text.strokeDasharray;
                    }else{
                        return DEFAULT_STROKE_DASHARRAY;
                    }
                    break;
                default:
            }
            return propValue;
        },
        // 设置node、link 样式
        setStyleForNodeOrLink: function(d,propName){
            var propValue = '';
            switch (propName) {
                case 'opacity':
                    if(d.style && d.style.opacity){
                        propValue = d.style.opacity;
                    }else{
                        propValue = DEFAULT_OPACITY_SHOW;
                    }
                    break;
                case 'stroke':
                    if(d.style && d.style.stroke){
                        propValue = d.style.stroke;
                    }else{
                        propValue = DEFAULT_STROKE;
                    }
                    break;
                case 'stroke-width':
                    if(d.style && d.style.strokeWidth){
                        return d.style.strokeWidth;
                    }else{
                        return DEFAULT_STROKE_WIDTH_SHOW;
                    }
                    break;
                case 'stroke-dasharray':
                    if(d.style && d.style.strokeDasharray){
                        return d.style.strokeDasharray;
                    }else{
                        return DEFAULT_STROKE_DASHARRAY;
                    }
                    break;
                case 'width':
                    if(d.style && d.style.icon && d.style.icon.key){
                        var icon = d.style.icon;
                        return (typeof icon.width === 'number')? icon.width : 12;
                    }
                    break;
                case 'height':
                    if(d.style && d.style.icon && d.style.icon.key){
                        var icon = d.style.icon;
                        return (typeof icon.height === 'number')? icon.height : 12;
                    }
                    break;
                case 'radius':
                    if(d.style && d.style.icon && d.style.icon.radius){
                        var radius = parseInt(d.style.icon.radius);
                        return isNaN(radius)?8:radius;
                    }else{
                        return DEFAULT_CIRCLE_RADIUS;
                    }
                    break;
                case 'fill':
                    if(d.style && d.style.icon && d.style.icon.key){
                        return 'url(#'+d.style.icon.key+')';
                    }else if(d.style && d.style.fill){
                        return d.style.fill;
                    }else{
                        return '#000';
                    }
                    break;
                default:

            }
            return propValue;
        },
        graphTick: function(event){
            // 关系名称
            forceLinkText.attr("x",function(d){return (d.source.x + d.target.x) / 2 ;})
                .attr("y",function(d){return (d.source.y + d.target.y) / 2 ;});
            // 关系
            forceLink.attr('d', function(d) {
                var deltaX = d.target.x - d.source.x,
                    deltaY = d.target.y - d.source.y,
                    dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
                    normX = deltaX / dist,
                    normY = deltaY / dist,
                    sourcePadding = 0,
                    targetPadding = 0;
                // 箭头方向为反向、双向时计算起始位置
                if(d.source.style && (d.source.style.icon || d.source.style.radius)
                    && (d.arrow === LINK_ARROW_REVERSE || d.arrow === LINK_ARROW_TWOWAY)){
                    var icon = d.source.style.icon,
                        radius = d.source.style.radius,
                        strokeWidth = icon.strokeWidth ? icon.strokeWidth : d.source.style.strokeWidth;
                    if(icon && (typeof icon.width === 'number')){
                        sourcePadding = icon.width / 2;
                    }else if(typeof radius === 'number'){
                        sourcePadding = radius ;
                    }
                    if(strokeWidth && strokeWidth.match(/\d+/)){
                        sourcePadding += parseInt(strokeWidth.match(/\d+/)[0],10);
                    }
                }
                // 箭头方向为正向、双向时计算目标位置
                if(d.target.style && (d.target.style.icon || d.target.style.radius)
                    && (d.arrow === LINK_ARROW_POSITIVE || d.arrow === LINK_ARROW_TWOWAY) ){
                    var icon = d.target.style.icon,
                        radius = d.target.style.radius,
                        strokeWidth = icon.strokeWidth? icon.strokeWidth : d.target.style.strokeWidth;
                    if(icon && (typeof icon.width === 'number')){
                        targetPadding = icon.width / 2;
                    }else if(typeof radius === 'number'){
                        targetPadding = radius ;
                    }
                    if(strokeWidth && strokeWidth.match(/\d+/)){
                        targetPadding += parseInt(strokeWidth.match(/\d+/)[0],10);
                    }
                }
                var sourceX = d.source.x + (sourcePadding * normX),
                    sourceY = d.source.y + (sourcePadding * normY),
                    targetX = d.target.x - (targetPadding * normX),
                    targetY = d.target.y - (targetPadding * normY);
                if(!isNaN(sourceX) && !isNaN(sourceY)&& !isNaN(targetX)&& !isNaN(targetY)){
                    return 'M' + sourceX + ',' + sourceY + 'L' + targetX + ',' + targetY;
                }
            });
            // 节点
            forceNode.attr("x", function(d) {
                        if(d.style && d.style.icon){
                            return d.x - d.style.icon.width/2;
                        }
                      })
                     .attr("y", function(d) {
                        if(d.style && d.style.icon){
                            return d.y - d.style.icon.height/2;
                        }
                      })
                     .attr("cx", function(d) {
                          if(!d.style || !d.style.icon){
                             return d.x;
                          }
                      })
                     .attr("cy", function(d) {
                         if(!d.style || !d.style.icon){
                            return d.y;
                         }
                     });
            // 节点title
            forceNodeText.attr("x",function(d){
                        if(d.style && d.style.icon){
                            var width = (typeof d.style.icon.width === 'number')?d.style.icon.width/2:10,
                                strokeWidth = (typeof d.style.icon.strokeWidth === 'number')?d.style.icon.strokeWidth:0;
                            return d.x - width - strokeWidth;
                        }else if(d.style && d.style.radius){
                            var strokeWidth = 0;
                            if(typeof d.style.strokeWidth === 'number'){
                                strokeWidth = d.style.strokeWidth;
                            }
                            return d.x - d.style.radius -strokeWidth;
                        }else{
                            return d.x-10;
                        }
                    })
                    .attr("y",function(d){
                        if(d.style && d.style.icon){
                            var height = (typeof d.style.icon.height === 'number')?d.style.icon.height/2:10,
                                strokeWidth = (typeof d.style.icon.strokeWidth === 'number')?d.style.icon.strokeWidth:0;
                            return d.y - height - strokeWidth;
                        }else if(d.style && d.style.radius){
                            var strokeWidth = 0;
                            if(typeof d.style.strokeWidth === 'number'){
                                strokeWidth = d.style.strokeWidth;
                            }
                            return d.y - d.style.radius -strokeWidth;
                        }else{
                            return d.y-10;
                        }
                    });
        },
        // 定义image
        defineImage: function(icon){
            var iconKey = icon.key;
            var iconDefine = graphSvg.select('.graphDefine').select('#'+iconKey+'');
            // 未定义则添加定义
            if(!iconDefine.size()){
                graphSvg.select('.graphDefine')
                        .append('pattern')
                        .attr('id',iconKey)
                        .attr('width',(typeof icon.width === 'number')? icon.width : 12)
                        .attr('height',(typeof icon.height === 'number')? icon.height : 12)
                        .append('image')
                        .attr('xlink:href',icon.href)
                        .attr('image-rendering','optimizeQuality')
                        .attr('width',(typeof icon.width === 'number')? icon.width : 12)
                        .attr('height',(typeof icon.height === 'number')? icon.height : 12);
            }
        },
        // 选中节点，模糊未选中
        selectedNodes: function(nodes){
            // nodes Array
            if(!Array.isArray(nodes)){
                nodes = [nodes];
            }
            // 去除全部选中
            graphSvg.selectAll('.link').classed('selected',false)
            graphSvg.selectAll('.node').classed('selected',false).attr('filter','');
            // 添加选中
            graphSvg.selectAll('.node').select(function(d){
                var selectedFlag = false;
                nodes.some(function(curNode){
                    if(d.id === curNode.id){
                        selectedFlag = true;
                        return true;
                    }
                });
                if(selectedFlag){
                    return this;
                }else{
                    return null;
                }
            }).classed('selected',true).attr('filter','url(#selectedFilter)');
            // 模糊未选中
            this.inactiveByNodes(nodes);
        },
        // 根据节点模糊
        inactiveByNodes: function(nodes){
            // 删除所有模糊
            graphSvg.selectAll('.inactive').classed('inactive',false);
            var relationNodes = [];
            // 模糊link
            graphSvg.selectAll('.link').select(function(d){
                var containSource = false,
                    containTarget = false,
                    source = d.source,
                    target = d.target;
                nodes.some(function(curNode){
                    if(curNode.id === source.id){
                        containSource = true;
                    }else if(curNode.id === target.id){
                        containTarget = true;
                    }
                });
                if(containSource){relationNodes.push(target);}
                if(containTarget){relationNodes.push(source);}
                if(containSource || containTarget){
                    return null;
                }else{
                    return this;
                }
            }).classed('inactive',true);
            var mergeNodes = nodes.concat(relationNodes);
            nodes = this.arrayUniqueById(mergeNodes);
            // 模糊node
            graphSvg.selectAll('.node').select(function(d){
                var containFlag = false;
                mergeNodes.some(function(curNode){
                    if(curNode.id === d.id){
                        containFlag = true;
                    }
                });
                if(containFlag){
                    return null;
                }else{
                    return this;
                }
            }).classed('inactive',true);
        },
        // 选中关系，模糊未选中
        selectedLinks: function(links){
            // links Array
            if(!Array.isArray(links)){
                links = [links];
            }
            // 去除全部选中
            graphSvg.selectAll('.link').classed('selected',false)
            graphSvg.selectAll('.node').classed('selected',false).attr('filter','');
            // 添加选中
            graphSvg.selectAll('.link').select(function(d){
                var selectedFlag = false;
                links.some(function(curLink){
                    if(d.id === curLink.id){
                        selectedFlag = true;
                        return true;
                    }
                });
                if(selectedFlag){
                    return this;
                }else{
                    return null;
                }
            }).classed('selected',true);
            // 模糊未选中
            this.inactiveByLinks(links);
        },
        // 根据节点模糊
        inactiveByLinks: function(links){
            // 删除所有模糊
            graphSvg.selectAll('.inactive').classed('inactive',false);
            // 相关节点
            var nodes = [];
            // 模糊link
            graphSvg.selectAll('.link').select(function(d){
                var containFlag = false,
                    source = d.source,
                    target = d.target;
                links.every(function(curLink){
                    if(curLink.id === d.id){
                        containFlag = true;
                        nodes.push(d.source);
                        nodes.push(d.target);
                    }
                });
                if(containFlag){
                    return null;
                }else{
                    return this;
                }
            }).classed('inactive',true);
            // 模糊node
            graphSvg.selectAll('.node').select(function(d){
                var containFlag = false;
                nodes.some(function(curNode){
                    if(curNode.id === d.id){
                        containFlag = true;
                        return true;
                    }
                });
                if(containFlag){
                    return null;
                }else{
                    return this;
                }
            }).classed('inactive',true);
        },
        // 数组去重
        arrayUniqueById: function(sourceArray){
            var seen = new Map();
            var newArray = [];
            sourceArray.filter(function(a){
                if(!seen.has(a.id)){
                    seen.set(a.id, 1);
                    newArray.push(a);
                    return true;
                }
            });
            return newArray;
        },
        // 改变大小
        resize: function( width, height){
            var oldWidth = graphWidth + 0,
                oldHeight = graphHeight + 0;
            // 设置画布宽高
            graphWidth = width;
            graphHeight = height;
            if(!this.graph)return;
    		// 重绘D3
    		this.graph.attr('width',graphWidth)
                      .attr('height',graphHeight);
            // 设置中心点
            // graph.force("center", d3.forceCenter(graphWidth/2,graphHeight/2));
            simulation.alpha(1).restart();
            var cx = (graphWidth - oldWidth) / 2,
    			cy = (graphHeight - oldHeight) / 2,
    			ck = 1;
    		// 缩放
    		if (zoomedTransform) {
    			var tfx = zoomedTransform.x,
    				tfy = zoomedTransform.y,
    				tfk = zoomedTransform.k;
    			cx = cx * tfk + tfx;
    			cy = cy * tfk + tfy;
    			ck = tfk;
    		}
    		this.graph.transition().duration(200).call(graphZoom.transform, d3.zoomIdentity.translate(cx, cy).scale(ck));
        },
        // 指定Graph力强度
        assignStrength: function(strength){
            // 设置力强度
            graphStrength = strength;
            if(!simulation)return;
            simulation.force('strength', d3.forceManyBody().strength(graphStrength));
            simulation.alpha(1).restart();
            // 缩放
            if(zoomedTransform){
                graphSvg.attr("transform",zoomedTransform);
            }
        },
        // 指定Graph斥力
        assignCharge: function(charge){
            // 设置力强度
            graphCharge = charge;
            if(!simulation)return;
            simulation.force('charge', d3.forceManyBody().strength(graphCharge));
            simulation.alpha(1).restart();
            // 缩放
            if(zoomedTransform){
                graphSvg.attr("transform",zoomedTransform);
            }
        },
        // 指定Graph线长度
        assignDistance: function(distance){
            // 设置线长度
            graphDistance = distance;
            if(!simulation)return;
            simulation.force('distance', d3.forceManyBody().distanceMin(graphDistance));
            simulation.alpha(1).restart();
            // 缩放
            if(zoomedTransform){
                graphSvg.attr("transform",zoomedTransform);
            }
        },
        // 重置brush
        showBrush: function(brushFlag){
            graphBrushFlag = (typeof brushFlag != 'undefined')? brushFlag : true;
            if(graphBrushFlag && graphBrush){
                graphBrush.on('start',this.brushStart).on('brush',this.brushMove).on('end',this.brushEnd);
                brushSvg.call(graphBrush).style('display','');
                this.graph.style('cursor','crosshair');
            }else if(graphBrush){
                graphBrush.on('start',null).on('brush',null).on('end',null);
                brushSvg.call(graphBrush.move, null).style('display','none');
                this.graph.style('cursor','pointer');
            }
        },
        // 选中数据
        selectedData: function(data){
            if(data && data.nodes && data.nodes.length){
                this.selectedNodes(data.nodes);
            }
            if(data && data.links && data.links.length){
                this.selectedLinks(data.links);
            }
            if(data && !data.nodes.length && !data.links.length){
                graphSvg.selectAll('.inactive').classed('inactive',false);
                graphSvg.selectAll('.node').classed('selected',false).attr('filter',null);
                graphSvg.selectAll('.link').classed('selected',false);
            }
        },
        // 清空图
        clear: function(){
            if(!simulation)return;
            graphData = {nodes:[],links:[]};
            this.redrawedForce();
        },
        // 添加数据
        setData: function(data){
            if(!simulation)return;
            graphData = data;
            this.redrawedForce();
        },
        // 追加数据
        appendData: function(data){
            if(!simulation)return;
            if(data.nodes && data.nodes.length){
                var mergeNodes = graphData.nodes.concat(data.nodes);
                graphData.nodes = this.arrayUniqueById(mergeNodes);
            }
            if(data.links && data.links.length){
                var mergeLinks = graphData.links.concat(data.links);
                graphData.links = this.arrayUniqueById(mergeLinks);
            }
            this.redrawedForce();
        },
        // 设置中心点
        setGraphCenter: function(x,y){
            if(!simulation)return;
            if(typeof x === 'number' && typeof y === 'number'){
                simulation.force("center", d3.forceCenter(x,y));
                simulation.alphaTarget(0).restart();
            }
        },
        // 还原缩放
        resetGraphZoom: function(){
            var t = d3.zoomIdentity.translate(0, 0).scale(1)
            this.graph.call(graphZoom.transform, t);
        }
    }
    var forceGraph = ForceGraph.constructor(graph,data);
    forceGraph.initGraph(graph,data);
    return forceGraph;
};
